#include<iostream>
#include<stdio.h>
#include<string>
#include<string.h>
#include<unistd.h>
#include<pthread.h>

using namespace std;

// int g_val = 100; 在未初始化区，低地址
// 添加__thread，可以将一个内置类型设置为线程局部存储
__thread int g_val = 100; // 局部存储在共享器，地址变大

std::string changeId(const pthread_t& pthreadId)
{
    char tid[128];
    snprintf(tid,sizeof tid,"0x%x",pthreadId);
    return tid;
}
void* start_routine(void* args)
{
    string threadName = static_cast<const char*>(args);
    // pthread_detach(pthread_self()); // 设置自己为分离状态
    int cnt = 5;
    while(true)
    {
        sleep(1);
        cout << threadName << " running..." << changeId(pthread_self()) << "g_val:" << g_val << " &g_val:" << &g_val << endl;
        g_val++;
    }
}

int main()
{
    pthread_t tid;
    pthread_create(&tid,nullptr,start_routine,(void*)"thread 1");
    pthread_detach(tid);// 谁创建谁分离
    // pthread_attr_t *attr
    string main_id = changeId(pthread_self());


    // sleep(2);// 要保持先线程先分离，再让主线程去join，就能看到主线程join失败了
    int n = pthread_join(tid,nullptr);// 一个线程要是被分离了，那么就不能被等待了
    cout << "errno : " << n << strerror(n) << endl;

    while(true)
    {
        cout <<  "main thread running...new thread id : " << changeId(tid) << " main thread id : " << main_id << "g_val:" << g_val << " &g_val:" << &g_val << endl;
        sleep(1);
    }
    return 0;
}




/////////////////////////////////////线程概念///////////////////////////////////

//线程等待 为什么需要线程等待？
// 已经退出的线程，其空间没有被释放，仍然在进程的地址空间内。
// 创建新的线程不会复用刚才退出线程的地址空间。

// 1.线程是可以等待的，等待的时候，join的等待的，阻塞式等待，如果不想等待呢？
// 分离线程(主线程或者新线程都能调用)
// 默认情况下，新创建的线程是joinable的，线程退出后，需要对其进行pthread_join操作，否则无法释放资源，从而造成系统泄漏。
// 如果不关心线程的返回值，join是一种负担，这个时候，我们可以告诉系统，当线程退出时，自动释放线程资源


/////////////////////////////////////接口//////////////////////////////////////

// 获取线程tid(谁调用我，我就显示谁的tid)
// const pthread_t pthread_self(void);

// 线程分离(如果不关心线程的返回值)
// int pthread_detach(pthread_t thread);

//int pthread_create(pthread_t *thread, const pthread_attr_t *attr,void *(*start_routine) (void *), void *arg);
// pthread_attr_t *attr ： 这里面就是一些联合体  --> 线程的属性，比较少，大部分在OS

/////////////////////////////////////pthread库//////////////////////////////////////

// pthread库，原生线程库(共享库) --> 磁盘文件
// 原生线程库中，可能要存在多个线程 -- 我所那个这些接口的创建了线程，别人也可以同时在用。(别人也能用这个库创建线程)
// 原生线程库也要对这些线程做管理
// Linux方案：用户级线程，用户关系的线程属性在库中，内核提供线程执行流的调度
// Linux用户级线程 ：内核轻量级进程 = 1 ：1

// 用户级线程id究竟是什么？
// 当我创建了线程，我一定是将这个库映射进了mm_struct的共享区中
// 所以tid是库中线程的起始地址
// 描述线程的结构体(库):
// 1.struct_pthread 
// 2.线程局部存储(全局变量，不共享)
// 3.线程栈(用的是线程自己这个栈线程有自己独立栈结构)(当线程执行完毕，返回值等存在这里，join就能在这拿数据)